package com.chaosyeb.server.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.chaosyeb.server.config.UploadConfig;
import com.chaosyeb.server.config.security.component.JwtTokenUtils;
import com.chaosyeb.server.mapper.AdminMapper;
import com.chaosyeb.server.mapper.AdminRoleMapper;
import com.chaosyeb.server.mapper.RoleMapper;
import com.chaosyeb.server.pojo.Admin;
import com.chaosyeb.server.pojo.AdminRole;
import com.chaosyeb.server.pojo.RespBean;
import com.chaosyeb.server.pojo.Role;
import com.chaosyeb.server.service.IAdminService;
import com.chaosyeb.server.utils.AdminUtils;
import com.chaosyeb.server.vo.RegisterVO;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletRequest;
import java.io.File;
import java.io.FileOutputStream;
import java.util.*;
import java.util.stream.Collectors;

/**
 * <p>
 * 服务实现类
 * </p>
 *
 * @author Chaos
 * @since 2021-12-04
 */
@Service
@Slf4j
public class AdminServiceImpl extends ServiceImpl<AdminMapper, Admin> implements IAdminService {

    @Autowired
    private UserDetailsService userDetailsService;
    @Autowired
    private AdminMapper adminMapper;
    @Autowired
    private RoleMapper roleMapper;
    @Autowired
    private AdminRoleMapper adminRoleMapper;
    @Autowired
    private PasswordEncoder passwordEncoder;
    @Autowired
    private JwtTokenUtils jwtTokenUtils;
    @Value("${jwt.tokenHead}")
    private String tokenHead;
    @Autowired
    private UploadConfig uploadConfig;

    /**
     * 登录
     *
     * @param code
     * @param username
     * @param password
     * @param request
     * @return
     */
    @Override
    public RespBean login(String username, String password, String code, HttpServletRequest request) {
        //session中获取验证码
        String captcha = (String) request.getSession().getAttribute("captcha");
        System.out.println("captcha:===" + captcha);
        System.out.println("code:===" + code);
        // 临时测试
        if (StringUtils.isEmpty(code)){
            return RespBean.error("验证码不能为空！");
        }
        // 判断code是否为空或者captcha忽略大小写比较后不相等
        if (StringUtils.isEmpty(code) || !captcha.equalsIgnoreCase(code)) {
            return RespBean.error("验证码输入错入，请重新输入！");
        }
        System.out.println("登录...");
        //登录 获取登录信息
        UserDetails userDetails = userDetailsService.loadUserByUsername(username);
        System.out.println("登录用户信息：" + userDetails);
        // 如果用户信息为空，或者登录输入的密码和用户信息里的密码不相等，返回error
        if (userDetails == null || !passwordEncoder.matches(password, userDetails.getPassword())) {
            return RespBean.error("用户名或密码不正确");
        }
        if (!userDetails.isEnabled()) {
            return RespBean.error("账号被禁用，请联系管理员");
        }
        //更新security用户对象---userDetails用户信息，null密码，userDetails.getAuthorities()获取用户权限列表
        UsernamePasswordAuthenticationToken authenticationToken = new
                UsernamePasswordAuthenticationToken(userDetails, null, userDetails.getAuthorities());
        // 重新设置全局authenticationToken
        SecurityContextHolder.getContext().setAuthentication(authenticationToken);

        //生成token
        String token = jwtTokenUtils.generatorToken(userDetails);
        Map<String, String> tokenMap = new HashMap<>();
        // 将token信息保存到tokenMap中，返回给前端
        tokenMap.put("token", token);
        tokenMap.put("tokenHead", tokenHead);
        return RespBean.success("登录成功", tokenMap);
    }

    /**
     * 根据用户名获取用户信息
     *
     * @param username
     * @return
     */
    @Override
    public Admin getAdminByUserName(String username) {

        QueryWrapper<Admin> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("username", username).eq("enabled", true);
        return adminMapper.selectOne(queryWrapper);

        /*return adminMapper.selectOne(new QueryWrapper<Admin>().eq("username", username)
                .eq("enabled", true));*/
    }

    /**
     * 根据用户id查询角色列表
     *
     * @param adminId
     * @return
     */
    @Override
    public List<Role> getRole(Integer adminId) {
        List<Role> role = roleMapper.getRole(adminId);
        return role;
    }

    /**
     * 获取操作员，并判断是否有权限
     *
     * @param keywords
     * @return
     */
    @Override
    public RespBean getAllAdmins(String keywords) {
        // 当前用户Id
        Integer adminId = AdminUtils.getCurrentAdmin().getId();
        // 判断用户是否拥有角色权限-->需要循环遍历所有操作员，检查是否包含没有权限的操作员
        //List<Admin> adminList = adminMapper.selectList(new QueryWrapper<Admin>().eq("adminId", adminId));
        List<Admin> idList = adminMapper.selectList(new QueryWrapper<Admin>().select("id"));
        List<Integer> idListNew = idList.stream().map(Admin::getId).collect(Collectors.toList());
        List<AdminRole> adminList = adminRoleMapper.selectList(new QueryWrapper<AdminRole>().select("adminId"));
        List<Integer> adminListNew = adminList.stream().map(AdminRole::getAdminId).collect(Collectors.toList());
        // 可以使用链式编程
        //List<Integer> idListTest = adminMapper.selectList(new QueryWrapper<Admin>().select("id")).stream().map(Admin::getId).collect(Collectors.toList());
        // 这样作比较后也能实现，但是没有找出是哪位操作员没有权限
        /*if (!CollectionUtils.containsAny(idList, adminId1)) {
            return RespBean.error("操作员没权限！");
        }
        if (!adminList.containsAll(idList)) {
            return RespBean.error("操作员没权限！");
        }*/
        // 源码尝试 CollctionUtils.diff();
        List<Integer> diff = new ArrayList<>();
        Iterator<Integer> iterator = idListNew.iterator();
        while (iterator.hasNext()) {
            Integer nextItem = iterator.next();
            if (!adminListNew.contains(nextItem)) {
                diff.add(nextItem);
            }
        }
        for (Integer id : diff) {
            // 根据不同值diff中的id，获取这个id的username
            String username = adminMapper.selectById(id).getUsername();
            // 拼接返回值
            String result = username + "操作员没权限，请添加权限！";
            if (!diff.isEmpty()) {
                return RespBean.error(result);
            }
        }
        /*//Integer rid = adminRoleMapper.selectById(adminId).getRid(); 这样写的话是默认的主键id，需要adminId做条件
        Integer rid = adminRoleMapper.selectOne(new QueryWrapper<AdminRole>().eq("adminId", adminId)).getRid();

        if (rid == null) {
            return RespBean.error("操作员没权限！");
        }*/
        //传入当前用户keywords以及登录的用户id
        List<Admin> allAdmins = adminMapper.getAllAdmins(adminId, keywords);
        if (!CollectionUtils.isEmpty(allAdmins)) {
            return RespBean.success("获取成功！", allAdmins);
        }
        return RespBean.error("数据获取失败！");
    }

    /**
     * 更新操作员角色
     *
     * @param adminId
     * @param rids
     * @return
     */
    @Override
    @Transactional
    public RespBean updateAdminRole(Integer adminId, Integer[] rids) {
        //先根据adminId删除
        adminRoleMapper.delete(new QueryWrapper<AdminRole>().eq("adminId", adminId));
        //再添加
        Integer result = adminRoleMapper.addAdminRole(adminId, rids);
        //如果相等，说明受影响的行数是一样的 说明添加成功
        if (rids.length == result) {
            return RespBean.success("更新成功！");
        }
        return RespBean.error("更新失败！");
    }

    /**
     * 更新用户密码
     *
     * @param oldPass
     * @param newPass
     * @param adminId
     * @return
     */
    @Override
    public RespBean updateAdminPassword(String oldPass, String newPass, Integer adminId) {
        // 获取admin
        Admin admin = adminMapper.selectById(adminId);
        BCryptPasswordEncoder encoder = new BCryptPasswordEncoder();
        // 判断旧密码是否正确
        if (encoder.matches(oldPass, admin.getPassword())) {
            String encode = encoder.encode(newPass);
            admin.setPassword(encode);
            int result = adminMapper.updateById(admin);
            if (result == 1) {
                return RespBean.success("更新成功！");
            }
        }
        return RespBean.error("更新失败！");
    }

    /**
     * 更新用户头像
     *
     * @param file
     * @param id
     * @param authentication
     * @return
     */
    @Override
    public RespBean updateUserFace(MultipartFile file, Integer id, Authentication authentication) {
        if (StringUtils.isEmpty(file)) {
            return RespBean.error("图片不能为空！");
        }
        Admin admin = adminMapper.selectById(id);
        if (StringUtils.isEmpty(admin)) {
            return RespBean.error("用户不存在！");
        }
        // 获取文件名并修改(获取后缀.jpg)
        String filename = file.getOriginalFilename();
        String newFileName = admin.getUsername() + filename.substring(filename.lastIndexOf("."));
        try {
            uploadFiles(file.getBytes(), uploadConfig.getUploadPath(), newFileName);
        } catch (Exception e) {
            e.printStackTrace();
        }
        String url = "/static/" + newFileName;
        admin.setUserFace(url);
        int result = adminMapper.updateById(admin);
        if (result == 1) {
            Admin principal = (Admin) authentication.getPrincipal();
            principal.setUserFace(url);
            SecurityContextHolder.getContext().setAuthentication(new UsernamePasswordAuthenticationToken
                    (admin, null, authentication.getAuthorities()));
            return RespBean.success("更新成功！--->url：" + url);
        }
        return RespBean.error("更新失败！");
    }

    /**
     * 添加用户-要加角色role
     *
     * @param registerVO
     * @return
     */
    @Override
    public RespBean register(RegisterVO registerVO) {
        // 判断用户是否已存在
        HashMap<String, Object> map = new HashMap<>();
        map.put("username", registerVO.getUsername());
        List<Admin> admins = adminMapper.selectByMap(map);
        System.out.println("===admins===" + admins);
        if (!CollectionUtils.isEmpty(admins) && admins != null) {
            return RespBean.error("用户已存在！");
        }
        //  判断输入是否为空
        if (registerVO.getName().isEmpty() || registerVO.getPassword1().isEmpty() || registerVO.getPhone().isEmpty()
                || registerVO.getUsername().isEmpty() || registerVO.getPassword2().isEmpty()) {
            return RespBean.error("参数不能为空！");
        }
        if (!registerVO.getPassword1().equals(registerVO.getPassword2())) {
            return RespBean.error("两次密码输入不一致，请重新输入！");
        }
        // VO转POJO 操作的是数据库
        Admin admin = new Admin();
        admin.setName(registerVO.getName());
        admin.setPhone(registerVO.getPhone());
        admin.setUsername(registerVO.getUsername());
        // 用户密码加密
        BCryptPasswordEncoder encoder = new BCryptPasswordEncoder();
        String encodePassed = encoder.encode(registerVO.getPassword1());
        admin.setPassword(encodePassed);
        admin.setCreateTime(registerVO.getCreateTime());
        admin.setUpdateTime(registerVO.getUpdateTime());
        // 获取当前用户
        Admin currentAdmin = AdminUtils.getCurrentAdmin();
        System.out.println("===currentAdmin===" + currentAdmin);
        admin.setCreateBy(currentAdmin.getCreateBy());
        // 注册
        if (adminMapper.register(admin)) {
            return RespBean.success("注册成功！");
        }
        return RespBean.error("注册失败！");
    }

    /**
     * 物理删除
     *
     * @param id
     * @return
     */
    @Override
    public RespBean deleteById(Integer id) {
        /*QueryWrapper<Admin> wrapper = new QueryWrapper<>();
        wrapper.eq("id", id);
        //Integer deleteId = adminMapper.selectById(id).getDeleted();
        //Integer deleteId = adminMapper.selectOne(wrapper).getDeleted();*/
        // 根据id判断deleted的值
        Integer deleteId = adminMapper.selectUserById(id);
        if (deleteId > 1){
            return RespBean.error("删除失败,该用户不存在！");
        }
        if (deleteId == 1) {
            if (adminMapper.deleteAdminById(id)) {
                return RespBean.success("删除成功！");
            }
        }
        return RespBean.error("删除失败,不可直接删除！");
    }

    /**
     * 上传图片
     *
     * @param file
     * @param filePath
     * @param fileName
     * @throws Exception
     */
    private static void uploadFiles(byte[] file, String filePath, String fileName) throws Exception {
        File targetFile = new File(filePath);
        if (!targetFile.exists()) {
            targetFile.mkdirs();
        }
        FileOutputStream out = new FileOutputStream(filePath + fileName);
        out.write(file);
        out.flush();
        out.close();
    }

}
